大家好,第一次發文往後請各位前輩多多指教,我文筆很糟,有手殘的地方請見諒。
首先先感謝朋友介紹Google Code Jam這活動,但錯過了沒機會參加到,還好Google還是開放讓人做題目,直接奉上題目網址了。
原題目
有個外星機器人使用指令來進行攻擊,預設攻擊為1,幸運的是我們知道他所擁有的指令為以下兩種:
輸入第一行T,為測試筆數,每筆包含整數D和一個字串P:盾牌所承受的最大總商和機器人指令。
輸出每筆資料,包含Case #x: y,其中x是測試筆數編號,y是目標所需最小數量,或是IMPOSSIBLE。
1 <= Ť <= 100 。
1 <= D <= pow(10,9)。
2 <= P的長度 <=30 。
P的字符是C或S。
時間限制:每個測試集20秒。
記憶體限制:1GB。
輸入:
6
1 CS
2 CS
1 SS
6 SCCSSC
2 CC
3 CSCSS
輸出:
Case #1: 1
Case #2: 0
Case #3: IMPOSSIBLE
Case #4: 2
Case #5: 0
Case #6: 5
由上面三點我們得知,我們剛開始所需要的資料為,多餘的攻擊、S的位置和S當時的攻擊。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 交換。
template<class T>
void Swap(T& t1, T& t2)
{
	T save = t1;
	t1 = t2;
	t2 = save;
}
// 處理
// command: 指令。(因為會變動到資料所以直接拷貝)
// attakData: 攻擊的位置.目前位置的攻擊。
// needShield: 目前所需要的盾牌量(多出來的攻擊)。
int Process(string command, vector<vector<int>>& attakData, int needShield)
{
	int count = 0;
    
    // 直到我們不需要盾牌。
	while (needShield > 0)
	{
       for (int index = attakData.size() - 1; index > -1; index--)
		{
            // 得取"S"的索引位置。
			int offset = attakData[index][0];
            
            // 判斷上一個是不是"C"("CS"我們才交換)。
			if (command[offset - 1] == 'C')
			{
                // 交換.更新"S"位置和光束的攻擊大小。
				Swap(command[offset], command[offset - 1]);
				count++;
				attakData[index][0] = offset - 1;
				attakData[index][1] >>= 1;
				needShield -= attakData[index][1];
				break;
			}
		}
	}
	return count;
}
// 設定資料。
// command: 指令。
// attakData: 攻擊的位置.目前位置的攻擊。
// attak: 目前總攻擊。
void SetData(const string& command, vector<vector<int>>& attakData, int& attak)
{
	int base = 1;
	for (size_t index = 0; index < command.length(); index++)
	{
		if (command[index] == 'C')
		{
			base <<= 1;
		}
		else if (command[index] == 'S')
		{
			vector<int> data(2);
			data[0] = index;
			data[1] = base;
			attak += base;
			attakData.push_back(data);
		}
	}
}
// 檢查.初始化所需資料。
// command: 指令。
// shield: 盾牌。
int Compute(string& command, const int shield)
{
    // 等於0為IMPOSSIBLE。
	if (command.length() == 0)
	{
		return -1;
	}
    
    // 得取S的位置.S當下攻擊和目前的總攻擊。
	vector<vector<int>> attakData;
	int attak = 0;
	SetData(command, attakData, attak);
    
    // 攻擊次數大於盾牌為IMPOSSIBLE(都是1也無法抵擋)。
	if (attakData.size() > shield)
	{
		return -1;
	}
    
    // 計算最小需要幾次。
	return Process(command, attakData, attak - shield);
}
// 輸入和輸出。
void Input()
{
	int count = 0;
	int shield = 0;
	string command = "";
	while (cin >> count)
	{
		for (int index = 0; index < count; index++)
		{
			if (cin >> shield >> command)
			{
				int result = Compute(command, shield);
                
				if (result == -1)
				{
					cout << "Case #" << index + 1 << ": " << "IMPOSSIBLE" << endl;
				}
				else
				{
					cout << "Case #" << index + 1 << ": " << result << endl;
				}
			}
		}
	}
}
int main()
{
	Input();
	return 0;
}

註:輸出部分要很注意Case #1 : N,N前面還有一個空格,測了一小時不過就是因為少了空格...。
這題我終於把 Bug 解掉,大小 Case 都通過了。![]()
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
    int c = 0;
    int testcase;
    scanf("%d", &testcase);
    while (testcase--)
    {
        int D;
        string P;
        scanf("%d", &D);
        cin >> P;
        int maxIndex = 0; //最大索引
        int index = 0;    //當前索引
        int sum = 0;      //總傷害
        int power = 1;    //能量強度
        int change = 0;   //交換次數
        //先計算總傷害
        for (int i = 0; i < P.size(); i++)
        {
            //充能
            if (P[i] == 'C')
            {
                power = power * 2;
            }
            //發射
            if (P[i] == 'S')
            {
                sum = sum + power;
            }
        }
        maxIndex = index = P.size() - 1;
        while (true)
        {
            //全部交換完畢
            if (index == 0)
            {
                break;
            }
            //損傷小於D
            if (sum <= D)
            {
                break;
            }
            //交換位置
            if (P[index] == 'S' && P[index - 1] == 'C')
            {
                P[index] = 'C';
                P[index - 1] = 'S';
                sum = sum - power + power / 2;
                //如果 index + 1 的位置是 S 可以再交換一次
                if (index + 1 <= maxIndex && P[index + 1] == 'S')
                {
                    index++;
                }
                change++;
                continue;
            }
            //由後往前退
            if (P[index] == 'C')
            {
                power = power / 2;
            }
            index--;
        }
        //印出結果
        if (sum > D)
        {
            printf("Case #%d: IMPOSSIBLE\n", c + 1);
        }
        else
        {
            printf("Case #%d: %d\n", c + 1, change);
        }
        c++;
    }
    //system("pause");
    return 0;
}
                                    我也分享一下解法XD
第一次解的時候是每次都去找“CS”去交換,
但是後來想一下,傷害最小的情況下是把S都換到最前面,
也就是每次攻擊傷害都是1的時候,
所以我把一開始指令每一次的傷害都記錄下來,
然後從最高的開始除上2,一直到盾牌擋得了傷害為止,
程式碼如下:
#接收到幾個指令
commandCount = int(input())
#跑迴圈一次接收一個指令
for case in range(1, commandCount+1):
    #接收這次的指令
    data = input()
    #把血量和指令分別取出來
    hp = int(data.split(" ")[0])
    command = data.split(" ")[1]
    
    #用來印出結果的地方
    def printStatus(status):
        print("Case #" + str(case) + ": " + str(status))
    
    #在做處理前先判斷出現的S數目有沒有大於血量,有的話怎麼換都不可能守護地球了
    if(command.count("S")>hp):
        printStatus("IMPOSSIBLE")
        continue
    
    #用一個陣列,等等拿來放指令中每次的S傷害值
    killArr = []
    #設定初始傷害值1
    basedKill = 1
    
    #去取指令中的每個動作
    for indexStr in command:
        #如果是S就把這一次的傷害放進陣列中
        if (indexStr=="S"):
            killArr.append(basedKill)
        #如果是C就把這一次目前傷害*2
        elif (indexStr=="C"):
            basedKill = basedKill*2
    
    #設定變換的次數
    changeCount = 0;
    '''
    去跑迴圈,一直到目前的盾牌可以扛下總傷害量為止
    '''
    while(sum(killArr)>hp):
        #把最後一次的傷害除於2,這樣就等於把最後的C和S換位置
        killArr[-1] = killArr[-1]/2
        #重新排序,讓傷害維持由小到大
        killArr.sort()
        #變換次數+1
        changeCount+=1
    
    #印出變換次數
    printStatus(changeCount)